/*
Web: http://www.jsForms.com
Copyright (C) 2008  Igor Demyanov (mailto:Igor.Demyanov@gmail.com)
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
jsForms.FixIEComponentTemplate = function(text)
{
	return text.replace((/<PROPERTIES/gi),'<DIV SPEC="P"')
		.replace((/<EVENTS/gi),'<DIV SPEC="E"')
		.replace((/<CONTENT/gi),'<DIV SPEC="C"')
		.replace((/<KEY/gi),'<DIV SPEC="K"')
		.replace((/<COMPONENT/gi),'<DIV SPEC="O"')
		.replace(/<\/(KEY)|(EVENTS)|(PROPERTIES)|(COMPONENT)/gi,'</DIV');
}

jsForms.ParseTemplateM4 = function(template){
	var getTagInt = /[^>]*/;
	var getTagEnd = />/g;
	var getTagName = /\w+/;
	var getAttributes = /\w+(=(("[^"]*")|('[^']*'))|)/g;
	var getAttrName = /\w*/;
	var fixSep1 = /\\"/g;
	var fixSep2 = /\\'/g;
	var refixSep1 = /\01/g;
	var refixSep2 = /\02/g;
	var isCloseTag = /\/>/g;
	
	var zipSpace = / +/g;
	template = template.replace(fixSep1, String.fromCharCode(01)).replace(fixSep2, String.fromCharCode(02));
	var items = template.split(/</g);
	/*Node:
	 isRoot
	 isTag
	 isTextContent
	 isText
	 Text
	 isComponent
	 Type
	 isContent
	 InTo
	 
	 isProperties
	 isEvents
	 isKey
	 Name
	 Value
	 Type
	 Tag
	 
	 Name
	 Parent
	 Attributes:{}
	 Children:[]
	 */
	function parseAttributes(attrList){
		var tmp = {};
		for (var i = 1; i < attrList.length; i++) {
			var attrRAW = attrList[i];
			var name = getAttrName.exec(attrRAW)[0].toUpperCase();
			if (name.length == attrRAW.length) {
				tmp[name] = {};
			}
			else {
				tmp[name] = {
					value: attrRAW.substring(name.length + 2, attrRAW.length - 1).replace(refixSep1, '\\"').replace(refixSep2, "\\'")
				}
				/*if (name == "CLASS") {
				 tmp[name].value = tmp[name].value.replace(zipSpace, ' ');
				 }*/
			}
		}
		return tmp;
	}
	
	function createText(text){
		var tmp = new jsForms.Node();
		tmp.isText = true;
		tmp.Text = text;
		tmp.Attributes = attrList;
		return tmp;
	}
	
	function createTag(attrList){
		var tmp = new jsForms.Node();
		tmp.isTag = true;
		var tmpA = attrList["NAME"];
		if (tmpA) {
			tmp.Name = tmpA.value;
		}
		tmp.Attributes = attrList;
		return tmp;
	}
	//DEBUG
	//var logTab='';
	//DEBUG
	
	var root = new jsForms.Node();
	root.isRoot = true;
	
	var directAcces = {
		COMPONENT: function(){
			node = new jsForms.Node();
			node.isComponent = true;
			var tmpA = attrList["TYPE"];
			if (tmpA) {
				node.Type = tmpA.value;
			}
			var tmpA = attrList["NAME"];
			if (tmpA) {
				node.Name = tmpA.value;
			}
			node.Attributes = attrList;
		},
		PROPERTIES: function(){
			node = new jsForms.Node();
			node.isProperties = true;
		},
		EVENTS: function(){
			node = new jsForms.Node();
			node.isEvents = true;
		},
		CONTENT: function(){
			node = new jsForms.Node();
			node.isContent = true;
			var tmpA = attrList["INTO"];
			if (tmpA) {
				node.InTo = tmpA.value;
			}
		},
		KEY: function(){
			node = new jsForms.Node();
			node.isKey = true;
			var tmpA = attrList["NAME"];
			if (tmpA) {
				node.Name = tmpA.value;
			}
			var tmpA = attrList["VALUE"];
			if (tmpA) {
				node.Value = tmpA.value;
			}
			else {
				node.Value = tagExt;
			}
			var tmpA = attrList["TYPE"];
			if (tmpA) {
				node.Type = tmpA.value;
			}
		}
	};
	
	var current = root;
	for (var i in items) {
		var item = items[i];
		
		if (item == '') {
			continue;
		}
		
		var fIndex = item.indexOf('>');//getTagEnd.exec(item);		getTagEnd.lastIndex
		if (fIndex == -1) {//Tag not completed?
			jsForms.error(item + ':Tag not completed');
		}
		
		var tagExt;
		if (fIndex + 1 == item.length) {
			tagExt = undefined;
		}
		else {
			tagExt = item.substring(fIndex + 1);
		}
		var tagInt = item.substring(0, fIndex);
		
		var attrList = tagInt.match(getAttributes);
		if (attrList == null) {
			jsForms.error(item + ':Tag not completed');
		}
		
		var tag = attrList[0].toUpperCase();
		var closeTagIndex = tagInt.lastIndexOf('/');// Save index
		if (closeTagIndex == 0) {//Close tag
			if (current.Tag != tag) {
				debugger;
				jsForms.error(item + ':Tag stack error, wait:"' + current.Tag + '",input:"' + tag + '"');
			}
			current = current.Parent;
			
			//DEBUG
			/*
			 logTab = logTab.substring(1);
			 jsForms.log(logTab+'</'+tag+'>');
			 */
			//DEBUG
		}
		else {
			attrList = parseAttributes(attrList);
			var node;
			var f = directAcces[tag];
			if (f)
			{
				f();
			}
			else {// Tag
				node = createTag(attrList);
			}
			node.Tag = tag;
			current.appendNode(node);
			//DEBUG
			//jsForms.log(logTab+node.NodeName);
			//DEBUG
			
			if (closeTagIndex != tagInt.length - 1) {
				current = node;
				//DEBUG
				//logTab =logTab+'\t';
				//DEBUG
			}
		}
		
		if (tagExt != undefined) {
			current.appendNode(createText(tagExt));
		}
	}
	return root;
}

jsForms.ParseTemplateM3 = function(template, options){
	//genName = true;
	var isGenName = (options!=undefined && options.GenName == true);
	var getTagInt = /[^>]*/;
	var getTagEnd = />/g;
	var getTagName = /\w+/;
	var getAttributes = /\w+((="[^"]*")|(='[^']*')|((?= )*)|(?=\/))/g;
	var getAttrName = /[^=]+/;
	var fixSep1 = /\\"/g;
	var fixSep2 = /\\'/g;
	var refixSep1 = /\01/g;
	var refixSep2 = /\02/g;
	var isCloseTag = /\/>/g;
	var isSpecTag = /c|p|e|k/i;
	var isComponent = /component/i;
	var isProperties = /properties/i;
	var isEvents = /events/i;
	var isContent = /content/i;
	var isKey = /key/i;
	var zipSpace = / +/g;
	template = template.replace(fixSep1, String.fromCharCode(01)).replace(fixSep2, String.fromCharCode(02));
	var items = template.split(/</g);
	/*Node:
	 isRoot
	 isTag
	 isTextContent
	 isText
	 	Text
	 isComponent
	 Type
	 isContent
	 InTo
	 
	 isProperties
	 isEvents
	 isKey
	 Name
	 Value
	 Type
	 Tag
	 
	 Name
	 Parent
	 Attributes:{}
	 Children:[]
	 */
	function parseAttributes(attrList){
		var tmp = {};
		for (var i = 1; i < attrList.length; i++) {
			var attrRAW = attrList[i];
			var name = getAttrName.exec(attrRAW)[0].toUpperCase();
			if (name.length == attrRAW.length) {
				tmp[name] = {};
			}
			else {
				tmp[name] = {
					value: attrRAW.substring(name.length + 2, attrRAW.length - 1).replace(refixSep1, '\\"').replace(refixSep2, "\\'")
				}
				if (name == "CLASS") {
					tmp[name].value = tmp[name].value.replace(zipSpace, ' ');
				}
			}
		}
		return tmp;
	}

	function createText(text){
		var tmp = new jsForms.Node('#TEXT');
		tmp.isText = true;
		tmp.Text = text;
		tmp.Attributes = attrList;
		return tmp;
	}
	function createKey(attrList, tagExt){
		var tmp = new jsForms.Node('<KEY>');
		tmp.isKey = true;
		if (attrList["NAME"]) {
			tmp.Name = attrList["NAME"].value;
			tmp.NodeName = '<KEY name="'+tmp.Name+'">';
		}
		if (attrList["VALUE"]) {
			tmp.Value = attrList["VALUE"].value;
		}
		else {
			tmp.Value = tagExt;
		}
		if (attrList["TYPE"]) {
			tmp.Type = attrList["TYPE"].value;
		}
		return tmp;
	}
	function createComponent(attrList){
		var type = '';
		if (attrList['TYPE']) {
			type = attrList['TYPE'].value;
		}
		var name = generationName(type, attrList);
		
		var tmp = new jsForms.Node(name);
		tmp.Type = type;
		tmp.isComponent = true;
		tmp.Tag = 'COMPONENT';
		if (attrList['NAME']) {
			tmp.Name = attrList['NAME'].value;
		}
		tmp.Attributes = attrList;
		return tmp;
	}
	function generationName(tag, attrList){
		if (isGenName !== true) {
			return tag;
		}
		var id = attrList["ID"];
		var classes = attrList["CLASS"];
		var name = '<' + tag;
		if (id != undefined) {
			name = name + '#' + id;
		}
		if (classes != undefined && $.trim(classes.value) != '') {
			name = name + '.' + classes.value.replace(zipSpace, '.');
		}
		name = name + '>';
		if (attrList['NAME']) {
			name = name + '[' + attrList['NAME'].value + ']';
		}
		return name;
	}
	function createTag(tag, attrList){
		var name = generationName(tag, attrList);
		
		var tmp = new jsForms.Node(name);
		tmp.isTag = true;
		if (attrList['NAME']) {
			tmp.Name = attrList['NAME'].value;
		}
		tmp.Attributes = attrList;
		return tmp;
	}
	function createContent(attrList){
		var name = '>content';
		var into;
		if (attrList['INTO']) {
			into = attrList['INTO'].value;
			name = name + '[' + into + ']';
		}
		var tmp = new jsForms.Node(name);
		tmp.InTo = into;
		tmp.isContent = true;
		return tmp;
	}
	//DEBUG
	//var logTab='';
	//DEBUG
	
	var root = new jsForms.Node();
	root.isRoot = true;
	
	var current = root;
	for (var i in items) {
		var item = items[i];

		if (item == '') {
			continue;
		}
		
		var fIndex = item.indexOf('>');//getTagEnd.exec(item);		getTagEnd.lastIndex
		if (fIndex == -1) {//Tag not completed?
			jsForms.error(item + ':Tag not completed');
		}
		
		var tagExt;
		if (fIndex + 1 == item.length) {
			tagExt = undefined;
		}
		else {
			tagExt = item.substring(fIndex + 1);
		}
		var tagInt = item.substring(0, fIndex);
				
		var attrList = tagInt.match(getAttributes);
		if (attrList == null) {
			jsForms.error(item + ':Tag not completed');
		}

		var tag = attrList[0].toUpperCase();
		var closeTagIndex = tagInt.lastIndexOf('/');// Save index
		if (closeTagIndex == 0) {//Close tag
			if (current.Tag != tag) {
				debugger;
				jsForms.error(item + ':Tag stack error, wait:"' + current.Tag + '",input:"' + tag + '"');
			}
			current = current.Parent;
			
			//DEBUG
			/*
			logTab = logTab.substring(1);
			jsForms.log(logTab+'</'+tag+'>');
			*/
			//DEBUG
		}
		else {
			attrList = parseAttributes(attrList);
			var node;
			if (isSpecTag.test(tag) == true) {// Component,Properties,Events,Content,Key - ?
				if (isComponent.test(tag) == true) {//isComponent
					node = createComponent(attrList);
				}
				else 
					if (isProperties.test(tag) == true) {//isProperties
						node = new jsForms.Node(tag);
						node.isProperties = true;
					}
					else 
						if (isEvents.test(tag) == true) {//isEvents
							node = new jsForms.Node(tag);
							node.isEvents = true;
						}
						else 
							if (isContent.test(tag) == true) {//isContent
								node = createContent(attrList);
							}
							else 
								if (isKey.test(tag) == true) {//isKey
									node = createKey(attrList, tagExt);
								}
								else {// Sorry, it is Tag
									node = createTag(tag, attrList);
								}
			}
			else {// Tag
				node = createTag(tag, attrList);
			}
			node.Tag = tag;
			current.appendNode(node);
			//DEBUG
			//jsForms.log(logTab+node.NodeName);
			//DEBUG
			
			if (closeTagIndex != tagInt.length - 1) {
				current = node;
				//DEBUG
				//logTab =logTab+'\t';
				//DEBUG
			}
		}
		
		if (tagExt != undefined) {
			current.appendNode(createText(tagExt));
		}
	}
	return root;
}

jsForms.ParseTemplateM2 = function(template)
{
	function createNode(name){
		return new jsForms.Node(name);
	}
	
	function createText(text){
		var tmp = createNode('#TEXT');
		tmp.isText = true;
		tmp.Text = text;
		return tmp;
	}
	function createKey(attrList, tagExt){
		var tmp = createNode('<KEY>');
		tmp.isKey = true;
		if (attrList["NAME"]) {
			tmp.Name = attrList["NAME"].value;
			tmp.NodeName = '<KEY name="'+tmp.Name+'">';
		}
		if (attrList["VALUE"]) {
			tmp.Value = attrList["VALUE"].value;
		}
		else {
			tmp.Value = tagExt;
		}
		if (attrList["TYPE"]) {
			tmp.Type = attrList["TYPE"].value;
		}
		return tmp;
	}
	function createComponent(attrList){
		var type = '';
		if (attrList['TYPE']) {
			type = attrList['TYPE'].value;
		}
		var name = generationName(type, attrList);
		
		var tmp = createNode(name);
		tmp.Type = type;
		tmp.isComponent = true;
		tmp.Tag = 'COMPONENT';
		if (attrList['NAME']) {
			tmp.Name = attrList['NAME'].value;
		}
		fillNodeAttr(tmp, attrList);
		return tmp;
	}
	function generationName(tag, attrList){
		if (genName !== true) {
			return tag;
		}
		var id = attrList["ID"];
		var classes = attrList["CLASS"];
		var name = '<' + tag;
		if (id != undefined) {
			name = name + '#' + id;
		}
		if (classes != undefined && $.trim(classes.value) != '') {
			name = name + '.' + classes.value.replace(zipSpace, '.');
		}
		name = name + '>';
		if (attrList['NAME']) {
			name = name + '[' + attrList['NAME'].value + ']';
		}
		return name;
	}
	function createTag(tag, attrList){
		var name = generationName(tag, attrList);
		
		var tmp = createNode(name);
		tmp.isTag = true;
		if (attrList['NAME']) {
			tmp.Name = attrList['NAME'].value;
		}
		fillNodeAttr(tmp, attrList);
		return tmp;
	}
	function createContent(attrList){
		var name = '>content';
		var into;
		if (attrList['INTO']) {
			into = attrList['INTO'].value;
			name = name + '[' + into + ']';
		}
		var tmp = createNode(name);
		tmp.InTo = into;
		tmp.isContent = true;
		return tmp;
	}
	//DEBUG
	//var logTab='';
	//DEBUG
	
	var root = createNode();
	root.isRoot = true;
	var current = root;
	
	
	function startTag( tagName, attrs, unary )
	{
		var node = createNode(tagName);
		current.appendNode(node);
		current=node;
	}
	function endTag( tag )
	{
		current = current.Parent;
	}
	function chars( text )
	{}
	HTMLParser(template,{
		start:startTag,
		end:endTag,
		chars:chars
	});
	return root;
}

jsForms.CreateCache_InitEventsPropertiesNew = function(comp,initFunctionArr,type,compType,compName)
{
	var itemsP = [];
	var itemsE = [];
	var itemsC = comp.childNodes;//comp.Children;
	for (var i = 0; i < itemsC.length; i++) {
		if (itemsC[i].getAttribute('spec')=='P')//itemsC[i].isProperties== true
		{
			var itemsCK = itemsC[i].childNodes;//.Children;
			for (var i = 0; i < itemsCK.length; i++) {
				if (itemsCK[i].getAttribute('spec') == 'K')//itemsCK[i].isKey == true
				{
					itemsP.push(itemsCK[i]);
				}
			}
		}else
		if (itemsC[i].getAttribute('spec')=='E')//itemsC[i].isProperties== true
		{
			var itemsCK = itemsC[i].childNodes;//.Children;
			for (var i = 0; i < itemsCK.length; i++) {
				if (itemsCK[i].getAttribute('spec') == 'K')//itemsCK[i].isKey == true
				{
					itemsE.push(itemsCK[i]);
				}
			}
		}
	}
	for (var i=0; i < itemsP.length ; i++)
	{
		var key = itemsP[i];
		//var keyName = key.Name;
		//var keyValue = key.Value;
		//var keyType = key.Type;
		var keyName = key.getAttribute('name');
		var keyValue = key.getAttribute('value');
		var keyType = key.getAttribute('type');
		try
		{
			if (key.getAttribute('disable')!= undefined)//if (key.Attributes['DISABLE']!= undefined)
			{
				continue;
			}

			if (keyValue== undefined||keyValue == null) 
			{
				keyValue = key.innerHTML;
			}
			//jsForms.log(compName+':InitProperties(name="'+keyName+'",value="'+keyValue+'",type="'+keyType+'")');
			var propertyInfo = jsForms.GetPropertyInfo(compType,keyName);
			if (!propertyInfo)
			{
				jsForms.error(compName+':'+compType+':"'+keyName+'" - Property not found');
				continue;
			}
			
			if (keyType == undefined || keyType == null)
			{
				keyType = propertyInfo.Type;
			}
			else
			{
				keyType = keyType.toUpperCase();
			}
			
			switch (keyType) {
			case 'OBJECT':
				jsForms.ComponentCache[type].Constants[compName+'_'+keyName] = eval('('+keyValue+')');
				keyValue = 'mvc.Clone(cacheT.Constants["'+compName+'_'+keyName+'"])';
				break;
			default:
				keyValue="'"+keyValue.replace(/"/g,'\\"').replace(/'/g,"\\'")+"'";
				break;
			}
			
			if (propertyInfo.isDirect == true)
			{
				initFunctionArr.push('newObj.P.'+keyName+'='+keyValue+';');
			}
			else
			if (propertyInfo.isSetter == true)
			{
				initFunctionArr.push('newObj.Set'+keyName+'('+keyValue+');');
			}
			else
			{
				jsForms.error(compName+':'+compType+':"'+keyName+'" - setter not defined');
				continue;
			}
		}
		catch(e)
		{
			jsForms.error(compName+':'+compType+':InitProperties(name="'+keyName+'",value="'+keyValue+'",type="'+keyType+'":'+e);
		}
	}
	
	for (var i=0; i < itemsE.length ; i++)
	{
		var key = itemsE[i];
		//var keyName = key.Name;
		//var keyValue = key.Value;
		var keyName = key.getAttribute('name');
		var keyValue = key.getAttribute('value');
		if (jsForms.Components[type][keyValue])
		{
			if (!jsForms.CheckEvent(compType,keyName))
			{
				jsForms.error(compName+':'+compType+':"'+keyName+'" - Event not found');
				continue;
			}
			initFunctionArr.push('newObj.E.'+keyName+'={obj:o, func: o[\''+keyValue+'\']};');
			//targetObj.Events[keyName] = {obj: parentObj, func:parentObj[keyValue]};
		}else
		{
			jsForms.error(compName+':'+compType+':InitEvents(name="'+keyName+'",value="'+type+'.'+keyValue+'")');
		}
	}
};

jsForms.CreateCache_IncludeComponentNew = function(comp,initFunctionArr,type,index)
{
		//debugger;
		var compType = comp.getAttribute('type');//comp.Type;
		var compName = comp.getAttribute('name');//comp.Name;
		var compClass = comp.className;

		if (compType==undefined)
		{
			jsForms.error(type+':Component type undefined!\n'+comp.innerHTML);
		}
		if (compName == undefined)
		{
			compName = '_C'+index;
			jsForms.log(type+':Component name undefined, auto generate name:"'+compName+'"');
		}
		
		initFunctionArr.push('var newObj=mvc.CreateComponent("'+compType+'","'+compName+'");');
		if (compClass!=undefined)
		{
			initFunctionArr.push('newObj[0].className=newObj[0].className+" '+compClass+'";');
		}

		initFunctionArr.push('o.C.' + compName + ' = newObj;');
		
		jsForms.CreateCache_InitEventsPropertiesNew(comp,initFunctionArr,type,compType,compName);
};
jsForms.CreateCache_CreateVisualNew = function(type,dom,options)
{
	if (!jsForms.Templates[type])
	{
		jsForms.CleanCache(type);
		jsForms.error('Not found "'+type+'" Component!');
	}
	
	var tmp = $(jsForms.FixIEComponentTemplate(jsForms.Templates[type]));

	if (tmp.length != 1)
	{
		jsForms.error('Only one root element!');
	}
	
	// Optimization 
	dom.push('var doc=document;var mvc=jsForms;var cacheT=mvc.ComponentCache.'+type+';');
	
	function createElement(de,num)
	{
		dom.push('var el'+num+'=doc.createElement("'+de.tagName+'");');
		if (de.className) {
			dom.push('el' + num + '.className="' + de.className + '";');
		}
		if (de.id != '' && de.id) {
			dom.push('el' + num + '.id="' + de.id + '";');
		}
		//debugger;
		for(var i=0; i<de.attributes.length; i++)
		{
			var attr = de.attributes[i];
			if (attr.specified && attr.nodeName!='id' && attr.nodeName!='class') {
				//element.setAttribute(attr.nodeName, attr.value);
				dom.push('el'+num+'.setAttribute("'+attr.nodeName+'","'+attr.value+'");');
				//jsForms.log(attr.nodeName + ':' + attr.value);
			}
			if (attr.nodeName =="name" && RootIsDefine)
			{
				dom.push('o.C["'+attr.value+'"]=$(el'+num+');');
			}
		}
	};
	function createTextElement(de,num)
	{
		//var sText = de.Text.replace(/"/g,'\\"').replace(/'/g,"\\'").replace(/\n/g,"\\n");
		var sText = de.data.replace(/"/g,'\\"').replace(/'/g,"\\'").replace(/\n/g,"\\n");
		dom.push('var el'+num+'=doc.createTextNode("'+sText+'");');
	}

	function createContent(comp)
	{
		var contents = comp.childNodes;//comp.Children;
		var compType = comp.getAttribute('type');//comp.Type;
		//getAttribute('spec')=='O'
		var start = count;
		for (var i = 0; i < contents.length; i++) {
			var item = contents[i];
			if(item.getAttribute('spec')=='C')//if (item.isContent != true)
			{
				continue;
			}
			var into = item.getAttribute('into');//item.InTo;
			if (into == undefined || into == null) {
				into = 'content';
			}
			debugger;
			if (!jsForms.CheckContent(compType,into))
			{
				jsForms.error(compType+':'+into+' - Content not found');
				continue;
			}

			dom.push('var el' + count + '=newObj.C.' + into + '[0];');
			jobList.push({
				skip: true
			});
			count++;
		
			var items = item.childNodes;//item.Children;
			for (var ii = 0; ii < items.length; ii++) {
				jobList.push({
					p: start,
					e: items[ii]
				});
			}
			count+=items.length;
			start++;
		}
	};
	
	/*Node:
	 	isRoot
	 	isTag
		 	Tag
	 	isText
		 	Text
	 	isComponent
	 	isContent
	 		InTo
		
		isProperties
		isEvents
		isKey
			Name
			Value
		
		Name
	 	Parent
	 	Attributes:{}
	 	Children:[]
	 */
	
	var RootIsDefine = false;
	var jobList = [{e:tmp[0]}];
	var index = 0;
	var count = 1;
	while (index < count)
	{
		var elem = jobList[index];
		if (elem.skip)
		{
			index++;
			continue;
		}

		if (elem.e.nodeType == 3) {//if (elem.e.isText == true) {//Text
			createTextElement(elem.e, index);
		}
		else {// Component or Tag?
			if (elem.e.getAttribute('spec')!='O') {//elem.e.isComponent;
				createElement(elem.e, index);
				var incCount = elem.e.childNodes.length;
				for (var i = 0; i < incCount/*elem.e.Children.length*/; i++) {
					jobList.push({
						p: index,
						e: elem.e.childNodes[i]
					});
				}
				count += incCount;
			}
			else {
				jsForms.CreateCache_IncludeComponentNew(elem.e, dom, type, index);
				dom.push('var el' + index + '=newObj[0];');
				if (options && options.designMode == true) {
					//dom.push('el' + index + '.setAttribute("tid","' + elem.e.Attributes['TID'].value + '");');
					dom.push('el' + index + '.setAttribute("tid","' + elem.e.getAttribute('TID') + '");');
				}
				createContent(elem.e);
			}
		}
		if (elem.p== undefined)
		{
			dom.push('var o=$(el'+index+');');
			dom.push('el'+index+'._OBJ=o;');
			dom.push('o.C={};o.E={};o.P={};');
			dom.push('o.Components=o.C;o.Events=o.E;o.Properties=o.P;');
			dom.push('if(compName){');
			dom.push('el'+index+'.setAttribute("name",compName);');
			dom.push('o._Name=compName;}o._Type="'+type+'";');
			jsForms.CreateCache_CopyFunction(type,dom);
			RootIsDefine = true;
		}
		else
		{
			dom.push('el'+elem.p+'.appendChild(el'+index+');');
		}
		index++;
	}
}

/*
 OLD 
 */

jsForms.CreateCache_CreateVisualOld = function(type,dom,options)
{
	if (!jsForms.Templates[type])
	{
		jsForms.CleanCache(type);
		jsForms.error('Not found "'+type+'" Component!');
		throw 'Not found "'+type+'" Component!';
	}
	var tmp;
	if (jsForms.IsCompatibilityMode) {
		tmp = $(jsForms.FixIEComponentTemplate(jsForms.Templates[type]));
	}else
	{
	 tmp = $(jsForms.Templates[type]);
	}
	
	if (tmp.length != 1)
	{
		jsForms.error('Only one root element!');
		throw 'Only one root element!';
	}
	
	// Optimization 
	dom.push('var doc=document;var mvc=jsForms;var cacheT=mvc.ComponentCache.'+type+';');
	
	function createElement(de,num)
	{
		dom.push('var el'+num+'=doc.createElement("'+de.tagName+'");');
		if (de.className) {
			dom.push('el' + num + '.className="' + de.className + '";');
		}
		if (de.id != '' && de.id) {
			dom.push('el' + num + '.id="' + de.id + '";');
		}
		//debugger;
		for(var i=0; i<de.attributes.length; i++)
		{
			var attr = de.attributes[i];
			if (attr.specified && attr.nodeName!='id' && attr.nodeName!='class') {
				//element.setAttribute(attr.nodeName, attr.value);
				dom.push('el'+num+'.setAttribute("'+attr.nodeName+'","'+attr.value+'");');
				//jsForms.log(attr.nodeName + ':' + attr.value);
			}
			if (attr.nodeName =="name" && RootIsDefine)
			{
				dom.push('o.C["'+attr.value+'"]=$(el'+num+');');
			}
		}
	};
	function createTextElement(de,num)
	{
		var sText = de.data.replace(/"/g,'\\"').replace(/'/g,"\\'").replace(/\n/g,"\\n");
		dom.push('var el'+num+'=doc.createTextNode("'+sText+'");');
	}
	
	function createContent(comp,compType)
	{
		var selector;
		if (jsForms.IsCompatibilityMode) {
			selector = '>div[@spec="C"]';
		}
		else {
			selector = '>content';
		}
		var contents = $(selector,comp);

		var start = count;
		for (var i = 0; i < contents.length; i++) {
			var item = contents[i];
			var into = item.getAttribute('into');
			if (into == undefined || into == null) {
				into = 'content';
			}
			if (!jsForms.CheckContent(compType,into))
			{
				var sError = compType+':'+into+' - Content not found';
				jsForms.error(sError);
				return;
			}

			dom.push('var el' + count + '=newObj.C.' + into + '[0];');
			jobList.push({
				skip: true
			});
			count++;
		}
		for (var i = 0; i < contents.length; i++) {
			var items = contents[i].childNodes;
			for (var ii = 0; ii < items.length; ii++) {
				jobList.push({
					p: start,
					e: items[ii]
				});
			}
			count+=items.length;
			start++;
		}
	};
	
	var RootIsDefine = false;
	var jobList = [{e:tmp[0]}];
	var index = 0;
	var count = 1;
	while (index < count)
	{
		var elem = jobList[index];
		if (elem.skip)
		{
			index++;
			continue;
		}

		//debugger;
		if (elem.e.nodeType == 3) {//Text
			createTextElement(elem.e, index);
		}
		else {// Component or Tag?
			var isComponent;
			if (jsForms.IsCompatibilityMode == true)
			{
				isComponent = elem.e.getAttribute('SPEC') == 'O';
			}
			else
			{
			 	isComponent = elem.e.tagName.toUpperCase() == "COMPONENT";
			}
			if (isComponent == false) {
				createElement(elem.e, index);
				
				for (var i = 0; i < elem.e.childNodes.length; i++) {
					jobList.push({
						p: index,
						e: elem.e.childNodes[i]
					});
				}
				count += elem.e.childNodes.length;
			}
			else {
				var comp = $(elem.e);
				jsForms.CreateCache_IncludeComponentOld(comp, dom, type, index);
				dom.push('var el' + index + '=newObj[0];');
				if (options && options.designMode == true) {
					dom.push('el' + index + '.setAttribute("tid","' + comp.attr('tid') + '");');
				}
				createContent(comp, elem.e.getAttribute('type'));
			}
		}
		if (elem.p== undefined)
		{
			dom.push('var o=$(el'+index+');');
			dom.push('el'+index+'._OBJ=o;');
			dom.push('o.C={};o.E={};o.P={};');
			dom.push('o.Components=o.C;o.Events=o.E;o.Properties=o.P;');
			dom.push('if(compName){');
			dom.push('el'+index+'.setAttribute("name",compName);');
			dom.push('o._Name=compName;}o._Type="'+type+'";');
			jsForms.CreateCache_CopyFunction(type,dom);
			RootIsDefine = true;
		}
		else
		{
			dom.push('el'+elem.p+'.appendChild(el'+index+');');
		}
		index++;
	}
};

jsForms.CreateCache_InitPropertiesOld = function(comp,initFunctionArr,type,compType,compName)
{
	var selector;
	if (jsForms.IsCompatibilityMode) {
		selector = '>div[@spec="P"] div[@spec="K"]';
	}
	else {
		selector = '>properties key';
	}
	
	var items = $(selector,comp);
	for (var i=0; i < items.length ; i++)
	{
		var key = items[i];
		var keyName = key.getAttribute('name');
		var keyValue = key.getAttribute('value');
		var keyType = key.getAttribute('type');
		try
		{
			if (key.getAttribute('disable')!= undefined)
			{
				return;
			}
			
			if (keyValue == null || keyValue== undefined) 
			{
				keyValue = key.innerHTML;
			}
			//jsForms.log(compName+':InitProperties(name="'+keyName+'",value="'+keyValue+'",type="'+keyType+'")');
			var propertyInfo = jsForms.GetPropertyInfo(compType,keyName);
			if (!propertyInfo)
			{
				var sError = compName+':'+compType+':"'+keyName+'" - Property not found';
				jsForms.error(sError);
				return;
			}
			
			if (keyType == undefined || keyType == null)
			{
				keyType = propertyInfo.Type;
			}
			else
			{
				keyType = keyType.toUpperCase();
			}
			
			switch (keyType) {
			case 'OBJECT':
				jsForms.ComponentCache[type].Constants[compName+'_'+keyName] = eval('('+keyValue+')');
				keyValue = 'mvc.Clone(cacheT.Constants["'+compName+'_'+keyName+'"])';
				break;
			default:
				keyValue="'"+keyValue.replace(/"/g,'\\"').replace(/'/g,"\\'")+"'";
				break;
			}
			
			if (propertyInfo.isDirect == true)
			{
				initFunctionArr.push('newObj.P.'+keyName+'='+keyValue+';');
			}
			else
			if (propertyInfo.isSetter == true)
			{
				initFunctionArr.push('newObj.Set'+keyName+'('+keyValue+');');
			}
			else
			{
				var sError = compName+':'+compType+':"'+keyName+'" - setter not defined';
				jsForms.error(sError);
				return;
			}
		}
		catch(e)
		{
			var sError = compName+':'+compType+':InitProperties(name="'+keyName+'",value="'+keyValue+'",type="'+keyType+'":'+e;
			jsForms.error(sError);
			throw sError;
		}
	}
};

jsForms.CreateCache_InitEventsOld= function (comp,initFunctionArr,type,compType,compName)
{
	var selector;
	if (jsForms.IsCompatibilityMode) {
		selector = '>div[@spec="E"] div[@spec="K"]';
	}
	else {
		selector = '>events key';
	}
	$(selector,comp).each(function (){
		var key = $(this);
		var keyName = key.attr('name');
		var keyValue = key.attr('value');
		if (jsForms.Components[type][keyValue])
		{
			if (!jsForms.CheckEvent(compType,keyName))
			{
				var sError = compName+':'+compType+':"'+keyName+'" - Event not found';
				jsForms.error(sError);
				return;
			}
			initFunctionArr.push('newObj.E.'+keyName+'={obj:o, func: o[\''+keyValue+'\']};');
			//targetObj.Events[keyName] = {obj: parentObj, func:parentObj[keyValue]};
		}else
		{
			var sError = compName+':'+compType+':InitEvents(name="'+keyName+'",value="'+type+'.'+keyValue+'")';
			jsForms.error(sError);
			throw sError;
		}
	});
};

jsForms.CreateCache_IncludeComponentOld = function(comp,initFunctionArr,type,index)
{
		//debugger;
		var compType = comp.attr('type');
		var compName = comp.attr('name');
		var compClass = comp.attr('class');
		//var autoName = false;
		if (!compType)
		{
			debugger;
			jsForms.error(type+':Component type undefined!\n'+comp[0].innerHTML);
			throw type+':Component type undefined!';
		}
		if (!compName)
		{
		//	autoName = true;
			compName = '_C'+index;
			jsForms.log(type+':Component name undefined, auto generate name:"'+compName+'"');
			//jsForms.error('Component name undefined!');
			//throw 'Component name undefined!';
		}
		
		initFunctionArr.push('var newObj=mvc.CreateComponent("'+compType+'","'+compName+'");');
		if (compClass)
		{
			initFunctionArr.push('newObj[0].className=newObj[0].className+" '+compClass+'";');
		}
//		if (!autoName) {
			initFunctionArr.push('o.C.' + compName + ' = newObj;');
//		}
		
		jsForms.CreateCache_InitPropertiesOld(comp,initFunctionArr,type,compType,compName);
		jsForms.CreateCache_InitEventsOld(comp,initFunctionArr,type,compType,compName);
};
 